/* nbioLogLib.h - header for non-blocking logging facility */

/*
 * Copyright (c) 2004-2005 Wind River Systems, Inc.
 *
 * The right to copy, distribute, modify or otherwise make use
 * of this software may be licensed only pursuant to the terms
 * of an applicable Wind River license agreement.
 */

/*
modification history
--------------------
01b,15mar05,dlk  Enable NBIO_QUEUE_FDS support (SPR #102646).
01a,19jul04,dlk  Written.
*/

#ifndef __INCnbioLogLibh
#define __INCnbioLogLibh

#include <semLib.h>
#include <stdarg.h>

/******************************   WARNING   ********************************\

  THIS MODULE IS EXPERIMENTAL.  Wind River makes no guarantee that the APIs
  described by this header will be supported, unchanged or at all, in future
  releases. Use at your own risk.

\******************************   WARNING   ********************************/

#ifdef __cplusplus
extern "C" {
#endif

/* Turn off various features to keep the size smaller */

#undef NBIO_OWN_FDS		/* (don't) maintain own array of fd's */
#undef NBIO_BLOCKING_ALLOCATION /* (don't) support blocking buffer alloc. */
#undef NBIO_GRACEFUL_TERMINATE  /* (don't) wait for all buffers to be returned
				   when terminating. */

#define NBIO_QUEUE_FDS		/* (do) pass file descriptor with message */

/*
 * Even if NBIO_QUEUE_FDS is not supported, nbioSync() may be of use
 * to wait for previously posted output to complete.
 */
#define NBIO_SYNC		/* support nbioSync() */

/*
 * The size of individual message blocks. More than one block
 * may be stringed together to form a message. This must be
 * a power of two. If it is changed, MSG_FD_NONE, MSG_FD_SYNC, MSG_FD,
 * and MSG_LEN may also need to be adjusted.
 */

#define MSG_BLOCK_SIZE	128

#define MSG_FD_NONE ((UINT32)0xffffff)
#define MSG_FD_SYNC ((UINT32)0xfffffe)

#define MSG_FD(x) ((int)(((UINT32)(x)) >> 8))
#define MSG_LEN(x) ((x) & 0xff)


/* Initial number of file descriptors in file descriptor table */

#define INIT_FDS	16

/* A LOG_MSG should be aligned on an MSG_SIZE boundary. */

union _MSG_BLOCK;

typedef struct _BLK_BLOCK
    {
    union _MSG_BLOCK * pNext;
    int numBlocks;
    } BLK_BLOCK;

typedef struct _MSG_BLOCK_HDR
    {
    union _MSG_BLOCK * pNext;	/* next message in list */
    UINT32 fdAndLen;		/* upper 24 bits: file desc; lower 8: len */
    } MSG_BLOCK_HDR;

typedef union _MSG_BLOCK
    {
    MSG_BLOCK_HDR hdr;
    BLK_BLOCK blk;
    char data [MSG_BLOCK_SIZE];
    } MSG_BLOCK;


#define MSG_DATA_SIZE	(MSG_BLOCK_SIZE - sizeof (MSG_BLOCK_HDR))

typedef struct _NBIO_INFO NBIO_INFO; /* semi-private */

typedef struct _MSG_INFO
    {
    int offset;			/* Current position in last block */
    NBIO_INFO * pInfo;		/* NBIO_INFO to use for allocation */
    MSG_BLOCK * pHead;		/* First block of message */
    MSG_BLOCK * pTail;		/* Last block of message */
    int timeout;		/* timeout in ticks, or WAIT_FOREVER */
    UINT32 fd;			/* Shifted FD value */
    } MSG_INFO;

typedef STATUS (*NBIO_BEGIN_FUNC) (MSG_INFO * pMsgInfo, int fd, int timeout);
typedef STATUS (*NBIO_END_FUNC) (MSG_INFO * pMsgInfo);
typedef int    (*NBIO_APPEND_FUNC) (MSG_INFO * pMsgInfo,
				    const char * fmt, ...);
typedef STATUS (*NBIO_DROP_FUNC) (MSG_INFO * pMsgInfo);
typedef STATUS (*NBIO_FLUSH_FUNC) (MSG_INFO * pMsgInfo);

typedef int    (*NBIO_FORMATV_FUNC) (MSG_INFO * pMsgInfo, const char * fmt,
				     va_list vaList);
typedef int    (*NBIO_OUTPUT_FUNC) (char * pInBuf, int inLen,
				    MSG_INFO * pMsgInfo);

typedef int    (*NBIO_LOG_FUNC) (const char * fmt, ...);
typedef int    (*NBIO_FDPRINT_FUNC) (int fd, int timeout,
				     const char * fmt, ...);
typedef STATUS (*NBIO_SYNC_FUNC) (void);
typedef STATUS (*NBIO_LOGFDSET_FUNC) (int fd);
typedef STATUS (*NBIO_LOGFDADD_FUNC) (int fd);
typedef STATUS (*NBIO_LOGFDDEL_FUNC) (int fd);

typedef struct _NBIO_FUNCS
    {
    NBIO_BEGIN_FUNC	begin;
    NBIO_END_FUNC	end;
    NBIO_APPEND_FUNC	append;
    NBIO_DROP_FUNC	drop;
    NBIO_FLUSH_FUNC	flush;
    NBIO_FORMATV_FUNC	formatV;
    NBIO_OUTPUT_FUNC	output;
    NBIO_LOG_FUNC	log;

#if defined (NBIO_QUEUE_FDS) || defined (NBIO_BLOCKING_ALLOCATION_SUPPORT)
    NBIO_FDPRINT_FUNC	fdPrint;
#endif

#ifdef NBIO_SYNC
    NBIO_SYNC_FUNC	sync;
#endif

#ifdef NBIO_OWN_FDS
    NBIO_LOGFDSET_FUNC  fdSet;
    NBIO_LOGFDADD_FUNC  fdAdd;
    NBIO_LOGFDDEL_FUNC  fdDel;
#endif
    } NBIO_FUNCS;

extern NBIO_FUNCS _api_nbio;

/* function prototypes */

extern STATUS	nbioLogInit (int fd, int initMsgs);

#if defined (NBIO_QUEUE_FDS) || defined (NBIO_BLOCKING_ALLOCATION_SUPPORT)
extern int	nbioFdPrint (int fd, int timeout, const char * fmt, ...);
#endif

extern int	nbioLog (const char * fmt, ...);

extern STATUS	nbioBegin (MSG_INFO * pMsgInfo, int fd, int timeout);
extern STATUS	nbioEnd (MSG_INFO * pMsgInfo);
extern int	nbioAppend (MSG_INFO * pMsgInfo, const char * fmt, ...);
extern STATUS	nbioDrop (MSG_INFO * pMsgInfo);
extern STATUS	nbioFlush (MSG_INFO * pMsgInfo);

extern int	nbioFormatV (MSG_INFO * pMsgInfo, const char * fmt,
			     va_list vaList);

extern int	nbioOutput (char * pInBuf, int inLen, MSG_INFO * pMsgInfo);

#ifdef NBIO_SYNC
extern STATUS	nbioSync (void);
#endif

#ifdef NBIO_OWN_FDS
extern STATUS	nbioLogFdSet (int fd);
extern STATUS	nbioLogFdDel (int fd);
extern STATUS	nbioLogFdAdd (int fd);
#endif

/* semi-private interfaces */

typedef struct _LOG_BUF_POOL
    {
    MSG_BLOCK * pHead;		/* list of available buffers */
#ifdef NBIO_BLOCKING_ALLOCATION_SUPPORT
    ULONG	want;		/* number of tasks waiting for buffers */
    SEM_ID      countSem;	/* used to wait for buffers or timeout */
    ULONG	reserved;	/* number of reserved buffers */
    MSG_BLOCK * pReserved;	/* buffers reserved for current waiters */
#endif
    ULONG	allocFails;	/* number of allocation failures (timeouts) */
    } LOG_BUF_POOL;

struct _NBIO_INFO
    {
    MSG_BLOCK * pFirst;		/* First queued message */
    MSG_BLOCK ** ppLast;	/* Pointer to pointer to last queued message */
    SEM_ID sync;		/* Synchronization semaphore */
    LOG_BUF_POOL pool;		/* pool of free buffers */
#ifdef NBIO_OWN_FDS
    int * pFds;			/* Pointer to array of file descriptors */
    int numFds;			/* Current number of file descriptors */
    int maxFds;			/* Size of file descriptor array */
    int theFd;			/* Distinguished logging file descriptor */
#endif
    int taskId;			/* Task ID of server task */
    MSG_BLOCK * pBlocks;	/* List of allocated blocks of messages */
    };

extern NBIO_INFO logInfo;

extern STATUS	nbioLogInfoInit (NBIO_INFO * pInfo, int initMsgs);
extern STATUS	nbioLogInfoMsgsAdd (NBIO_INFO * pInfo, int numBlocks);
extern STATUS	nbioLogServerInit (NBIO_INFO * pInfo, int initialFds,
				  int priority,	 int options,
				  int stack, const char * name);
extern void	nbioLogInfoTerminate (NBIO_INFO * pInfo);
#ifdef NBIO_SYNC
extern STATUS	nbioLogInfoSync (NBIO_INFO * pInfo);
#endif

#ifdef NBIO_OWN_FDS
extern STATUS	nbioLogInfoFdSet (NBIO_INFO * pInfo, int fd);
extern STATUS	nbioLogInfoFdDel (NBIO_INFO * pInfo, int fd);
extern STATUS	nbioLogInfoFdAdd (NBIO_INFO * pInfo, int fd);
#endif

#ifdef __cplusplus
}
#endif

#endif /* __INCnbioLogLibh */
